package com.cloudxingkong.dianyinke.Student.Utils;

import android.content.Context;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AdapterView;
import android.widget.FrameLayout;
import android.widget.ListView;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by qq923 on 2016/2/25.
 *
 */
public class MySwipeView extends FrameLayout {
    private View contentView,deleteView; //内容区域、删除区域、不需要手动通过addView方式，以为已经在布局文件中加入
    private int contentViewHeight,contentViewWidth,deleteViewWidth; //内容区域的宽高度，删除区域的宽度
    private ViewDragHelper viewDragHelper= ViewDragHelper.create(this, new MyCallBack());
    private SwipeState swipeState= SwipeState.Closed; //用于标记当前的开关状态，默认是关闭
    private ListView listView; //它所依赖的listview

    public void setListView(ListView listView) {
        this.listView = listView;
    }

    public MySwipeView(Context context) {
        super(context);
    }

    public MySwipeView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MySwipeView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    /**
     * 布局文件加载完成之后的回调，但是只是加载完成布局
     * 自己具体宽高不知道，只知道自己内部有什么控件
     */
    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        contentView=getChildAt(0);  //获取到内容区域
        deleteView=getChildAt(1);   //获取到删除区域
    }

    /**
     * 这里的时候已经知道控件宽高
     * @param w
     * @param h
     * @param oldw
     * @param oldh
     */
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        contentViewHeight=contentView.getMeasuredHeight(); //获取内容区域和删除区域的测量高度
        contentViewWidth=contentView.getMeasuredWidth();  //获取内容区域的测量宽度
        deleteViewWidth=deleteView.getMeasuredWidth(); //删除区域的宽度
    }

    /**
     * 摆放内部子控件的位置
     * @param changed
     * @param left
     * @param top
     * @param right
     * @param bottom
     */
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        quickClose();
    }

    @Override
    public boolean onInterceptHoverEvent(MotionEvent event) {
        return viewDragHelper.shouldInterceptTouchEvent(event);  //交给helper来处理拦截事件
    }
    private int lastX,lastY,clickX,clickY;  //记录滑动时候的xy坐标、记录点击时候的xy坐标
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int x= (int) event.getX();
        int y= (int) event.getY();
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                lastX=clickX= (int) event.getX();
                lastY=clickY= (int) event.getY();
                break;
            case MotionEvent.ACTION_UP:
                //抬起手指
                int upX = (int) event.getX();
                int upY = (int) event.getY();
                if (upX==clickX&&upY==clickY){ //如果按下去的xy坐标和抬起的xy坐标一致，则代表是点击事件
                    //在这里要执行listview的item点击事件
                    //获取设置的item点击事件
                    AdapterView.OnItemClickListener onItemClickListener = listView.getOnItemClickListener();
                    //AdapterView.OnItemLongClickListener onItemLongClickListener = listView.getOnItemLongClickListener();
                    if (onItemClickListener != null) {
                        int position = (int) getTag(getId());
                        onItemClickListener.onItemClick(listView,this,position,position);
                    }
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if (Math.abs(x-lastX)>Math.abs(y-lastY)){  //左右滑动的距离差 大于上下  交给自己处理
                    getParent().requestDisallowInterceptTouchEvent(true);
                }else{
                    getParent().requestDisallowInterceptTouchEvent(false);
                }
                break;

        }
        viewDragHelper.processTouchEvent(event);  //由helper处理事件
        return true;
    }

    private class MyCallBack extends ViewDragHelper.Callback{
        /**
         * 用于判断触摸的子控件是否是可以拖动的
         * @param child 当前触摸的子控件
         * @param pointerId
         * @return  如果返回true  代表当前触摸的子控件可以被拖动，否则不可拖动
         */
        @Override
        public boolean tryCaptureView(View child, int pointerId) {
            return child==contentView||child==deleteView;
        }

        /**
         * 当view的位置发生变化的回调
         * @param changedView  变化的view
         * @param left  当前的getLeft
         * @param top  当前的getTop
         * @param dx   d drag   拖动的x的值
         * @param dy    拖动的y值
         */
        @Override
        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
            if (changedView==contentView){ //当拖动内容区域的时候，手动变化删除区域
                deleteView.layout(deleteView.getLeft()+dx,deleteView.getTop(),deleteView.getRight()+dx,deleteView.getBottom());
            } else if (changedView == deleteView) { //如果拖动的删除区域，应该手动滑动内容区域
                contentView.layout(contentView.getLeft()+dx,contentView.getTop(),contentView.getRight()+dx,contentView.getBottom());
            }
            if (contentView.getLeft() == 0&&swipeState!= SwipeState.Closed) { //关闭状态
                swipeState= SwipeState.Closed;
                unClosedSwipeViews.remove(MySwipeView.this);
            } else if (contentView.getLeft() == -deleteViewWidth&&swipeState!= SwipeState.Open) { //打开状态
                swipeState= SwipeState.Open;
                for (int i = 0; i < unClosedSwipeViews.size(); i++) { //打开后遍历集合，将不说自己的控件全部关闭
                    if (unClosedSwipeViews.get(i)!=MySwipeView.this){
                        unClosedSwipeViews.get(i).close();
                    }
                }
                if (!unClosedSwipeViews.contains(MySwipeView.this)){//当前集合里面已经打开的控件不包含自己
                    //在此应该先把已经打开的关掉
                    unClosedSwipeViews.add(MySwipeView.this);
                }

            }else{
                swipeState= SwipeState.Swiping;
                for (int i = 0; i < unClosedSwipeViews.size(); i++) { //打开后遍历集合，将不说自己的控件全部关闭
                    //遍历所有已经打开并且滑动方向是往左滑 才执行
                    //如果不加方向的判断，自动关闭回去的那个控件，又会把我们打开的控件关闭掉
                    if (unClosedSwipeViews.get(i)!=MySwipeView.this&&dx<0){
                        unClosedSwipeViews.get(i).close();
                    }
                }
                if (!unClosedSwipeViews.contains(MySwipeView.this)){//当前集合里面已经打开的控件不包含自己
                    //在此应该先把已经打开的关掉
                    unClosedSwipeViews.add(MySwipeView.this);
                }
            }
            super.onViewPositionChanged(changedView, left, top, dx, dy);
        }

        /**
         * 抬起手指或者是事件被拦截释放后的回调
         * @param releasedChild  触摸的View
         * @param xvel  释放时候的 xy
         * @param yvel
         */
        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
            if (contentView.getLeft()<-deleteViewWidth/2){  //删除区域滑出一半
                open();
            }else{
                close();
            }
            super.onViewReleased(releasedChild, xvel, yvel);
        }


        /**
         * 用于返回被和触摸的view到底滑动多少的回调
         * 关键
         * @param child  被触摸的控件
         * @param left  当前控件理论上的getLeft
         * @param dx    滑动的距离
         * @return   默认为0  如果返回left就一切按照系统默认的拖动速度，拖多少动多少
         */
        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {
            if (child == contentView) {
                if (left>0) left=0;  //如果大于0 则等于9
                if (left<-deleteViewWidth) left = -deleteViewWidth; //如果是左滑动超过了deleteView的宽度就等于它的宽度
            }else{
                if (left>contentViewWidth) left=contentViewWidth;  //删除区域滑动的最大值，如果超出内容区域的宽度，则为内容区域的宽度
                if (left<contentViewWidth-deleteViewWidth) //如果小于内容区域的宽度减去删除区域的宽度，则代表已经完全滑出了，不应该再变了
                    left = contentViewWidth-deleteViewWidth; //
            }
            return left;
        }

        /**
         * 获取view的水平拖拽方位
         * @param child 触摸的控件
         * @return  默认返回值是0  0的话代表内部子控件不能滑动
         */
        @Override
        public int getViewHorizontalDragRange(View child) {
            return deleteViewWidth;
        }
    }

    /**
     * scroll滑动时候的调用
     */
    @Override
    public void computeScroll() {
        if (viewDragHelper.continueSettling(true)) {
            ViewCompat.postInvalidateOnAnimation(MySwipeView.this); //刷新界面
        }
        super.computeScroll();
    }

    /**
     * 记录滑动状态的枚举
     * 打开、关闭、滑动
     */
    enum SwipeState{
        Open,Closed,Swiping
    }

    //用于存放非关闭状态的控件
    public static List<MySwipeView> unClosedSwipeViews=new ArrayList<>();

    /**
     * 打开状态
     */
    public void open(){
        //参数一： 目标控件
        viewDragHelper.smoothSlideViewTo(contentView,-deleteViewWidth,0);
        ViewCompat.postInvalidateOnAnimation(MySwipeView.this);  //刷新界面
    }

    /**
     * 关闭控件
     */
    public void close(){
        viewDragHelper.smoothSlideViewTo(contentView,0,0);
        ViewCompat.postInvalidateOnAnimation(MySwipeView.this);
    }

    /**
     * 快速关闭
     */
    public void quickClose(){
        contentView.layout(0,0,contentViewWidth,contentViewHeight); //重新摆放内容区域
        deleteView.layout(contentViewWidth,0,contentViewWidth+deleteViewWidth,contentViewHeight);  //重新摆放删除区域
        unClosedSwipeViews.remove(this); //手动移除 ，因为手动layout不会导致viewdraghelper里面的回调执行
    }
}
